﻿function TrackBall(arguments) {
	var container;		//容器
	var lineLen;		//线段长度
	var lineDis;		//线段间距
	var lineNum;		//线段数量
	var ballNum;		//移动球数量
	var ballId;			//移动球位置
	var ballDis;		//移动球间距
	var trackPath;		//轨道路径
	var trackLine;		//轨道线
	var trackPoint;		//轨道点
	var moveBall;		//移动球
	var speed;			//移动速度
	var moveCirStyle;	//移动球样式
	var lineStyle;		//线段样式
	var cirStyle;		//轨道点样式
	var isMove;			//是否在移动
	//获取轨道路径
	var getTrackPath = function(pots) {
		var path = [];
		var p0 = pots[0].p0;
		for(var i = 0; i < pots.length; i++) {
			var pot = pots[i];
			var add = 1 / (container.width() * parseInt(pot.width.replace('%', '')) / 100);
			pot.p0 = p0;
			for(var t = 0; t <= 1; t += add) {
				path.push(pot.p0 * Math.pow((1 - t), 3) + 3 * pot.p1 * t * Math.pow(1 - t, 2) + 3 * pot.p2 * Math.pow(t, 2) * (1 - t) + pot.p3 * Math.pow(t, 3));
			}
			p0 = path[path.length - 1];
		}
		return path;		
	}
	//绘制轨道
	var drawTrack = function() {
		//绘制线段
		var dragLine = function(x1, y1, x2, y2) {
			var svgLine = '<line class="line" x1="' + x1 + '" y1="' + y1 + '" x2="' + x2 + '" y2="' + y2 + '" style="stroke:' + lineStyle.stroke + '; stroke-width:' + lineStyle.width + '"/>';
			return svgLine;
		}
		//绘制圆形
		var dragCircle = function(cx, cy) {
			var svgCircle = '<circle class="circle" cx="' + cx + '" cy="' + cy + '" r="' + cirStyle.r + '" stroke="' + cirStyle.stroke + '" stroke-width="' + cirStyle.width + '" fill="' + cirStyle.fill + '"style="cursor: pointer;"/>';
			return svgCircle;
		}
		//绘制移动圆形
		var dragMoveCircle = function(cx, cy) {
			var svgCircle = '<circle class="moveCircle" cx="' + cx + '" cy="' + cy + '" r="' + moveCirStyle.r + '" stroke="' + moveCirStyle.stroke + '" stroke-width="' + moveCirStyle.width + '" fill="' + moveCirStyle.fill + '" style="cursor: pointer"/>';
			return svgCircle;		
		}
		//绘制SVG
		var svg = '<svg width="100%" height="100%">';
		var len = trackPath.length;
		ballDis = Math.floor((len - moveCirStyle.r * 2 - 1) / (ballNum - 1));
		lineNum = 0;
		lineDis += lineLen; 
		for(var i = moveCirStyle.r; i < len; i++) {
			var x2 = i + lineLen;
			if(x2 < len) {
				var x1 = i;
				var y1 = trackPath[i];
				var y2 = trackPath[x2];
				svg += dragLine(x1, y1, x2, y2);
				i += lineDis;
				lineNum++;
			}
		}
		for(var i = moveCirStyle.r; i < len; i += ballDis) {
			svg += dragCircle(i, trackPath[i]);
		}		
		var cx = 0 * ballDis + moveCirStyle.r;
		svg += dragMoveCircle(cx, trackPath[cx]);	
		svg += '</svg>';
		container.html(svg);
		trackLine = container.find('line.line');
		trackPoint = container.find('circle.circle');
		moveBall = container.find('circle.moveCircle');
	}
	//设置轨道点
	var setTrackPoint = function(callback) {
		trackPoint.click(function() {
			setMoveBall($(this).index() - lineNum, callback);
		});
	}
	//设置移动球
	var setMoveBall = function(id, callback) {
		var form = ballId * ballDis;
		var to = id * ballDis;
		var getLineId = function() {
			for(var i = 0; i < lineNum; i++) {
				if(trackLine.eq(i).attr('x2') >= form) {
					return i;
				}
			}
		}
		lineId = getLineId();
		//向左移动
		var renderLeft = function() {	
			form -= speed;
			if(form < to) {
				form = to;
			}
			var cx = form + moveCirStyle.r;
			moveBall.attr('cx', cx);
			moveBall.attr('cy', trackPath[cx]);
			var len = ballId - speed;
			if(len < 0) {
				len = 0;
			}
			for(var i = ballId; i >= len; i--) {
				var p = trackPoint.eq(i);
				if(p.attr('cx') >= cx) {
					p.attr('fill', cirStyle.fill);
					ballId--;
				}
			}
			len = lineId - speed;
			if(len < 0) {
				len = 0;
			}
			for(var i = lineId; i >= len; i--) {
				var l = trackLine.eq(i);
				if(l.attr('x2') >= cx) {
					l.attr('style', 'stroke: ' + lineStyle.stroke + '; stroke-width:' + lineStyle.width);
					lineId--;
				}
			}
			if(form == to){
				isMove = false;
				ballId++;
				lineId++;
				if(typeof callback == 'function') {
					callback(id);
				}
			} else {
				requestAnimationFrame(renderLeft);
			}
		}
		//向右移动
		var renderRight = function() {
			form += speed;
			if(form > to) {
				form = to;
			}
			var cx = form + moveCirStyle.r;
			moveBall.attr('cx', cx);
			moveBall.attr('cy', trackPath[cx]);
			var len = ballId + speed;
			if(len > ballNum) {
				len = ballNum;
			}
			for(var i = ballId; i < len; i++) {
				var p = trackPoint.eq(i);
				if(p.attr('cx') <= cx) {
					p.attr('fill', moveCirStyle.fill);
					ballId++;
				}
			}
			len = lineId + speed;
			if(len > lineNum) {
				len = lineNum;
			}
			for(var i = lineId; i < len; i++) {
				var l = trackLine.eq(i);
				if(l.attr('x2') <= cx) {
					l.attr('style', 'stroke: ' + moveCirStyle.fill + '; stroke-width:' + lineStyle.width);
					lineId++;
				}
			}
			if(form == to) {
				isMove = false;
				ballId--;
				lineId--;
				if(typeof callback == 'function') {
					callback(id);
				}				
			} else {
				requestAnimationFrame(renderRight);
			}
		}
		if(! isMove) {
			isMove = true;
			if(id < ballId) {
				requestAnimationFrame(renderLeft);
			} else {
				requestAnimationFrame(renderRight);
			}
		}
	}
	//构造函数
	this.trackBall = function(arguments) {
		container = arguments.container;
		var pots = arguments.pots || [
			{
				p0: 170,
				p1: 100,
				p2: 100,
				p3: 170,
				width: '100%'
			}
		];
		lineStyle = arguments.lineStyle || {
			stroke: 'rgb(255, 255, 255)',
			width: 2		
		}
		cirStyle = arguments.cirStyle || {
			r: 6,
			stroke: 'rgb(255, 255, 255)',
			width: 0,
			fill: 'rgb(255, 255, 255)'
		}
		moveCirStyle = arguments.moveCirStyle || {
			r: 8,
			stroke: 'rgb(244, 192, 43)',
			width: 0,
			fill: 'rgb(244, 192, 43)'		
		}
		lineLen = arguments.lineLen || 5;
		lineDis = arguments.lineDis || 5;
		ballNum = arguments.ballNum || 7;
		ballId = 0;
		isMove = false;
		speed = arguments.speed || 10;
		trackPath = getTrackPath(pots);
		drawTrack();
		setTrackPoint(arguments.callback);
		setMoveBall(arguments.ballId || 0, arguments.callback);
	}
	this.trackBall(arguments || {});
}